﻿<!--
> Muaz Khan     - https://github.com/muaz-khan 
> MIT License   - https://www.webrtc-experiment.com/licence/
> Experiments   - https://github.com/muaz-khan/WebRTC-Experiment
-->

<!DOCTYPE html>
<html id="home" lang="en">

    <head>
        <title>RTCDataChannel for Beginners | Muaz Khan</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
        <link rel="author" type="text/html" href="https://plus.google.com/+MuazKhan">
        <meta name="author" content="Muaz Khan">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <link rel="stylesheet" href="https://cdn.webrtc-experiment.com/style.css">
        <style>
            p { padding: .8em; }

            li {
                border-bottom: 1px solid rgb(189, 189, 189);
                border-left: 1px solid rgb(189, 189, 189);
                padding: .5em;
            }

            td {
                border: 0;
                padding: 0;
            }
        </style>
        <!-- for HTML5 el styling -->
        <script>
            document.createElement('article');
            document.createElement('footer');
        </script>

        <script type="text/javascript" src="https://cdn.webrtc-experiment.com/syntax/sh_main.min.js"> </script>
        <script type="text/javascript" src="https://cdn.webrtc-experiment.com/syntax/sh_javascript.min.js"> </script>
        <script type="text/javascript" src="https://cdn.webrtc-experiment.com/syntax/sh_html.min.js"> </script>
        <link type="text/css" rel="stylesheet" href="https://cdn.webrtc-experiment.com/syntax/sh_style.css">
		
    </head>

    <body onload="sh_highlightDocument();">
        <article>
            <header style="text-align: center;">
                <h1>RTCDataChannel for Beginners</h1>
                <p>
                    <a href="https://www.webrtc-experiment.com/">HOME</a>
                    <span> &copy; </span>
                    <a href="http://www.MuazKhan.com/" target="_blank">Muaz Khan</a>
                        
                    .
                    <a href="http://twitter.com/WebRTCWeb" target="_blank" title="Twitter profile for WebRTC Experiments">@WebRTCWeb</a>
                        
                    .
                    <a href="https://github.com/muaz-khan?tab=repositories" target="_blank" title="Github Profile">Github</a>
                        
                    .
                    <a href="https://github.com/muaz-khan/WebRTC-Experiment/issues?state=open" target="_blank">Latest issues</a>
                        
                    .
                    <a href="https://github.com/muaz-khan/WebRTC-Experiment/commits/master" target="_blank">What's New?</a>
                </p>
            </header>
				
            <div class="github-stargazers"></div>

            <blockquote style="background: #f3b7b7;border: 5px solid black;border-radius: 5px;">
                This tutorial is <span style="border: 1px dotted red; background: yellow; padding: 2px 5px;">out-dated (written in 2013)</span>. Please check this tutorial instead: <a href="https://codelabs.developers.google.com/codelabs/webrtc-web/#0">https://codelabs.developers.google.com/codelabs/webrtc-web/#0</a>
            </blockquote>

            <table style="width: 100%;">
                <tr>
                    <td>If you're newcomer, newbie or beginner; you're suggested to try <a href="http://www.rtcmulticonnection.org/docs/" target="_blank">RTCMultiConnection.js</a> or <a href="https://github.com/muaz-khan/WebRTC-Experiment/tree/master/DataChannel" target="_blank">DataChannel.js</a> libraries.
                    </td>
                </tr>
            </table>

            <table>
                <tr>
                    <td>
                        <h2>Try RTCDataChannel on Chrome</h2>

                    </td>
                </tr>

                <tr>
                    <td>Copy below code and paste in Console Tab of Chrome Dev Tools (using Ctrl + Shift + i).<br />
                        <br />
                        <pre class="sh_javascript">
var iceServers = {
    iceServers: [{
        url: 'stun:stun.l.google.com:19302'
    }]
};

var optionalRtpDataChannels = {
    optional: [{
        RtpDataChannels: true
    }]
};

var offerer = new webkitRTCPeerConnection(iceServers, optionalRtpDataChannels),
    answerer, answererDataChannel;

var offererDataChannel = offerer.createDataChannel('RTCDataChannel', {
    reliable: false
});
setChannelEvents(offererDataChannel, 'offerer');

offerer.onicecandidate = function (event) {
    if (!event || !event.candidate) return;
    answerer && answerer.addIceCandidate(event.candidate);
};

var mediaConstraints = {
    optional: [],
    mandatory: {
        OfferToReceiveAudio: false, // Hmm!!
        OfferToReceiveVideo: false // Hmm!!
    }
};

offerer.createOffer(function (sessionDescription) {
    offerer.setLocalDescription(sessionDescription);
    createAnswer(sessionDescription);
}, null, mediaConstraints);


function createAnswer(offerSDP) {
    answerer = new webkitRTCPeerConnection(iceServers, optionalRtpDataChannels);
    answererDataChannel = answerer.createDataChannel('RTCDataChannel', {
        reliable: false
    });

    setChannelEvents(answererDataChannel, 'answerer');

    answerer.onicecandidate = function (event) {
        if (!event || !event.candidate) return;
        offerer && offerer.addIceCandidate(event.candidate);
    };

    answerer.setRemoteDescription(offerSDP);
    answerer.createAnswer(function (sessionDescription) {
        answerer.setLocalDescription(sessionDescription);
        offerer.setRemoteDescription(sessionDescription);
    }, null, mediaConstraints);
}

function setChannelEvents(channel, channelNameForConsoleOutput) {
    channel.onmessage = function (event) {
        console.debug(channelNameForConsoleOutput, 'received a message:', event.data);
    };

    channel.onopen = function () {
        channel.send('first text message over RTP data ports');
    };
    channel.onclose = function (e) {
        console.error(e);
    };
    channel.onerror = function (e) {
        console.error(e);
    };
}
</pre>
                    </td>
                </tr>

                <tr>
                    <td>After executing above code in the console; try to send messages over RTP data ports like this:
                        <br />
                        <br />
                        <pre class="sh_javascript">
offererDataChannel.send('message from offerer');
answererDataChannel.send('message from answerer');
</pre>
                    </td>
                </tr>

                <tr>
                    <td>
                        <h2>Try RTCDataChannel on Firefox</h2>
                    </td>
                </tr>

                <tr>
                    <td>Copy below code and paste in Console Tab of Firefox Dev Tools (using Ctrl + Shift + i).
                        <br />
                        <br />
                        <pre class="sh_javascript">
function setChannelEvents(channel, channelNameForConsoleOutput) {
    channel.onmessage = function (event) {
        console.debug(channelNameForConsoleOutput, 'received a message:', event.data);
    };
    channel.onopen = function () {
        channel.send('first text message over SCTP data ports');
    };
}

function useless() {}

var iceServers = {
    iceServers: [{
            url: 'stun:23.21.150.121'
        }
    ]
};

var offerer = new mozRTCPeerConnection(iceServers),
    answerer, answererDataChannel, offererDataChannel;

offererDataChannel = offerer.createDataChannel('channel', {});
offererDataChannel.binaryType = 'blob';
setChannelEvents(offererDataChannel, 'offerer');

navigator.mozGetUserMedia({
    audio: true,
    fake: true
}, function (stream) {
    offerer.addStream(stream);

    offerer.createOffer(function (sessionDescription) {
        offerer.setLocalDescription(sessionDescription);
        createAnswer(sessionDescription);
    }, null, mediaConstraints);

}, useless);

var mediaConstraints = {
    optional: [],
    mandatory: {
        OfferToReceiveAudio: true,
        OfferToReceiveVideo: true
    }
};

function createAnswer(offerSDP) {
    answerer = new mozRTCPeerConnection(iceServers);
    answerer.ondatachannel = function (event) {
        answererDataChannel = event.channel;
        answererDataChannel.binaryType = 'blob';
        setChannelEvents(answererDataChannel, 'answerer');
    };

    navigator.mozGetUserMedia({
        audio: true,
        fake: true
    }, function (stream) {

        answerer.addStream(stream);
        answerer.setRemoteDescription(offerSDP);

        answerer.createAnswer(function (sessionDescription) {
            answerer.setLocalDescription(sessionDescription);

            offerer.setRemoteDescription(sessionDescription);
        }, null, mediaConstraints);

    }, useless);
}		
</pre>
                    </td>
                </tr>

                <tr>
                    <td>After executing above code in the console; try to send messages over SCTP data ports like this:
                        <br />
                        <br />
                        <pre class="sh_javascript">
offererDataChannel.send('message from offerer');
answererDataChannel.send('message from answerer');
</pre>
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2>Explanation:</h2>
                        <br />
                        <blockquote>
                            There are following possible situations:
                            <ol>
                                <li>A person wants to chat with his friend(s); share files directly; or <strong>share a part of the screen in realtime</strong>!
                                    <br />
                                    He is the <a href="#offerer">offerer</a>.
                                </li>
                                <li>A person who receives an offer from a friend: so, he will join him. He is the <a href="#answerer">answerer</a>.
                                </li>
                            </ol>
                            There are so many other possible situations. Let us go to the point.
                        </blockquote>
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2>Offerer</h2>
                    </td>
                </tr>
                <tr>
                    <td>
                        <blockquote>
                            The first situation: a person wants to make an offer request to his friend. He will create <a href="#offer-sdp">offer sdp</a> and send that <a href="#offer-sdp">sdp</a> to his friend.
                        </blockquote>
                        <blockquote>
                            First of all: we need to open a peer connection:
                        </blockquote>
                        <pre class="sh_javascript">
var <span id="peerConnection">peerConnection</span> = new <strong id="Strong1" title="Initializing RTCPeerConnection object. You'll do this both for offerer and answerer.">webkitRTCPeerConnection</strong>(
    { "<strong title="ICE servers for NAT traversing">iceServers</strong>": [{ "url": "<strong title="Using STUN as ICE server for NAT traversing">stun</strong>:stun.l.google.com:19302" }] },
    { <strong>optional</strong>: [{ <strong id="RtpDataChannels">RtpDataChannels</strong>: true}] }
);
</pre>

                        <blockquote>
                            RTCPeerConnection constructor takes two objects:
                            <ol>
                                <li>ICE servers (STUN or TURN)
                                </li>
                                <li>
                                    <strong>Optional</strong> (like <a href="#RtpDataChannels">RtpDataChannels</a>)
                                </li>
                            </ol>
                        </blockquote>
                    </td>
                </tr>
                <tr>
                    <td>
                        <blockquote>
                            Setting event handlers for <a href="#peerConnection">peer connection</a> object:
                        </blockquote>
                        <pre class="sh_javascript">
<a href="#peerConnection">peerConnection</a>.<strong title="On getting locally generated ICE candidates: You'll post these locally generated ICE to other peer; so he can add them and ask peer connection object to recognize suitable ICE candidate and complete the handshake.">onicecandidate</strong> = <a href="#onicecandidate-func" id="onicecandidate">onicecandidate</a>;
<a href="#openDataChannel">openDataChannel</a>();
</pre>

                        <blockquote>
                            In simple words: <a href="#onicecandidate-func">onicecandidate</a> returns locally generated ICE candidates so you can pass them over other peer(s) via XHR or Socket.
                        </blockquote>
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2><a href="#openDataChannel">openDataChannel</a></h2>
                    </td>
                </tr>
                <tr>
                    <td>
                        <pre class="sh_javascript">
var <strong id="channel">channel</strong>;
function <strong id="openDataChannel">openDataChannel</strong>() {
    if (!<a href="#peerConnection">peerConnection</a> || typeof <a href="#peerConnection">peerConnection</a>.<strong>createDataChannel</strong> == '<strong>undefined</strong>') {
        console.log('RTCDataChannel is not enabled. Use Chrome Canary '+
                    'and enable this flag via chrome://flags');
        return;
    }

    <a href="#channel">channel</a> = <a href="#peerConnection">peerConnection</a>.<strong>createDataChannel</strong>('<strong title="JUST a label for channel. You can choose your own. For more than one channels over same peer: This value MUST be unique.">RTCDataChannel</strong>',
        {
            <strong title="Currently Google Chrome only supports unreliable (UDP-like) channels....reliable (TCP-like) channels coming soon." id="unreliable">reliable</strong>: false
        }
    );

    <a href="#channel">channel</a>.<strong title="Data transferred by RTCDataChannel (SCTP protocol)">onmessage</strong> = function (event) {
        console.log(event.<strong title="You should call event.data to get access to data transferred.">data</strong>);
    };

    <a href="#channel">channel</a>.<strong title="SCTP is ready. DataChannel is opened. Start sharing text, data, files or screen.">onopen</strong> = function (event) {
        <a href="#channel">channel</a>.<strong title="You can send data by calling channel.send method.">send</strong>('RTCDataChannel opened.');
    };
    
    <a href="#channel">channel</a>.<strong title="RTCDataChannel is closed.">onclose</strong> = function (event) {
        console.log('RTCDataChannel closed.');
    };
    
    <a href="#channel">channel</a>.<strong title="Something went wrong. May be slow internet connection. Or other kinds of error.">onerror</strong> = function (event) {
        console.error(event);
    };

    <a href="#peerConnection">peerConnection</a>.<strong>ondatachannel</strong> = function () {
        console.log('peerConnection.ondatachannel event fired.');
    };
}
</pre>
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2>How to send data?</h2>
                    </td>
                </tr>
                <tr>
                    <td>
                        <pre class="sh_javascript">
<a href="#channel">channel</a>.<strong title="You can send data by calling channel.send method.">send</strong>('JUST a text message');
<a href="#channel">channel</a>.<strong title="You can send data by calling channel.send method.">send</strong>(
    JSON.<strong>stringify</strong>(
        {
            boolean: true, 
            integer: 1, 
            string: 'Wow!', 
            obj: { etc: 'etcetera' }
        }
    )
);
</pre>
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2>Creating Offer SDP</h2>
                    </td>
                </tr>
                <tr>
                    <td>
                        <pre class="sh_javascript">
<a href="#peerConnection">peerConnection</a>.<strong id="offerer">createOffer</strong>(function (sessionDescription) {
    <a href="#peerConnection">peerConnection</a>.<strong>setLocalDescription</strong>(sessionDescription);

    <span class="comment" id="offer-sdp" title="Offerer generated Offer SDP. So, now you should transfer that SDP on the answerer side. Answer will set his remote description using offer sdp.">// POST-Offer-SDP-For-Other-Peer(sessionDescription.<strong>sdp</strong>, sessionDescription.<strong>type</strong>);</span>

}, null, { '<strong>mandatory</strong>': { '<strong>OfferToReceiveAudio</strong>': true, '<strong>OfferToReceiveVideo</strong>': true } });
</pre>
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2>Answerer</h2>
                    </td>
                </tr>
                <tr>
                    <td>
                        <blockquote>
                            Assume that you sent <a href="#offer-sdp">offer sdp</a> to your friend using XHR. Now, "process" that <a href="#offer-sdp">offer sdp</a> and then create <a href="#answer-sdp">answer sdp</a> and send <a href="#answer-sdp">it</a> back to <a href="#answer-sdp-for-offerer">offerer</a>:
                        </blockquote>
                        <pre class="sh_javascript">
<a href="#peerConnection">peerConnection</a>.<strong>setRemoteDescription</strong>(new <strong>RTCSessionDescription</strong>(<a href="#offer-sdp">offerSDP</a>));

<a href="#peerConnection">peerConnection</a>.<strong id="answerer">createAnswer</strong>(function (sessionDescription) {
    <a href="#peerConnection">peerConnection</a>.<strong>setLocalDescription</strong>(sessionDescription);
    
    <span class="comment" id="answer-sdp" title="Answerer generated the Answer SDP. So, now you should transfer that SDP on the offerer side. Offer will set his remote description using answer sdp and complete the handshake.">// POST-answer-SDP-back-to-Offerer(sessionDescription.<strong>sdp</strong>, sessionDescription.<strong>type</strong>);</span>

}, null, { '<strong>mandatory</strong>': { '<strong>OfferToReceiveAudio</strong>': true, '<strong>OfferToReceiveVideo</strong>': true } });
</pre>
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2 id="answer-sdp-for-offerer">Offerer received <a href="#answer-sdp">answer sdp</a> from <a href="#answerer">answerer</a></h2>
                    </td>
                </tr>
                <tr>
                    <td>
                        <pre class="sh_javascript">
<a href="#peerConnection">peerConnection</a>.<strong>setRemoteDescription</strong>(new <strong>RTCSessionDescription</strong>(<a href="#answer-sdp">answerSDP</a>));
</pre>
                    </td>
                </tr>
                <tr>
                    <td>
                        <a href="#offer-sdp">Offer</a>/<a href="#answer-sdp">Answer</a> exchange is done. What remaining are ICE candidates.
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2>On getting locally generated ICE</h2>
                    </td>
                </tr>
                <tr>
                    <td>
                        <pre class="sh_javascript">
function <a href="#onicecandidate" id="onicecandidate-func">onicecandidate</a>(event) {
    if (!<a href="#peerConnection">peerConnection</a> || !event || !event.candidate) return;
    var candidate = event.<strong>candidate</strong>;
    <span class="comment" id="Span1" title="Local ICE candidates are generated. Now, you should pass these ICE on the other side and let other peer to add these ICE.">// POST-ICE-to-other-Peer(candidate.<strong>candidate</strong>, candidate.<strong>sdpMLineIndex</strong>);</span>
}
</pre>
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2>On getting ICE sent by other peer</h2>
                    </td>
                </tr>
                <tr>
                    <td>
                        <pre class="sh_javascript">
<a href="#peerConnection">peerConnection</a>.<strong id="addIceCandidate">addIceCandidate</strong>(new <strong>RTCIceCandidate</strong>({
    <strong>sdpMLineIndex</strong>: candidate.<strong>sdpMLineIndex</strong>,
    <strong>candidate</strong>: candidate.<strong>candidate</strong>
}));
</pre>
                    </td>
                </tr>
                <tr>
                    <td>
                        <h2>A few tips:</h2>
                    </td>
                </tr>
                <tr>
                    <td>
                        <ol>
                            <li>
                                <code>createDataChannel</code> must be called before creating offer-sdp.
                            </li>
                            <li>Maximum length for a single message over RTP data ports is about <a href="https://code.google.com/p/chromium/codesearch#chromium/src/third_party/libjingle/source/talk/media/sctp/sctpdataengine.cc&l=52" target="_blank">1280</a> bytes (chars).
                            </li>
                            <li>On RTP data ports, you can't send data over more than one channel simultaneously.
                            </li>
                            <li>Because RTP-channels are currently <a href="#unreliable" title="Currently Google Chrome only supports unreliable (UDP-like) channels....reliable (TCP-like) channels coming soon.">unreliable</a>...so be careful because it is "<strong>unordered (UDP-Like)</strong>" delivery of messages!
                            </li>
                        </ol>
                    </td>
                </tr>
                <tr>
                    <td>
                        <blockquote>
                            Are you interested in a "more" simple full-fledged guide? Read <a href="https://www.webrtc-experiment.com/docs/how-to-use-rtcpeerconnection-js-v1.1.html">this document</a>.
                        </blockquote>
                    </td>
                </tr>
                <tr>
                    <td>
                        <blockquote>
                            Are you interested in a "simple" guide about RTCDataChannel? Read <a href="https://www.webrtc-experiment.com/docs/how-to-use-rtcdatachannel.html">this document</a>.
                        </blockquote>
                    </td>
                </tr>

                <tr>
                    <td>Are you interested to learn <a href="https://www.webrtc-experiment.com/docs/how-file-broadcast-works.html" target="_blank">How to share files using RTCDataChannel APIs?</a>
                    </td>
                </tr>

            </table>

            <section style="border: 1px solid rgb(189, 189, 189); border-radius: .2em; margin: 1em 3em;">
                <h2 id="feedback" style="border-bottom: 1px solid rgb(189, 189, 189); padding: .2em .4em;">Feedback</h2>
                <div>
                    <textarea id="message" style="border: 1px solid rgb(189, 189, 189); height: 8em; margin: .2em; outline: none; resize: vertical; width: 98%;" placeholder="Have any message? Suggestions or something went wrong?"></textarea>
                </div>
                <button id="send-message" style="font-size: 1em;">Send Message</button><small style="margin-left: 1em;">Enter your email too; if you want "direct" reply!</small>
            </section>
        </article>
        
        <a href="https://github.com/muaz-khan/WebRTC-Experiment" class="fork-left"></a>
        
        <footer>
            <p>
                <a href="https://www.webrtc-experiment.com/">WebRTC Experiments</a>
                © <a href="https://plus.google.com/+MuazKhan" rel="author" target="_blank">Muaz Khan</a>
                <a href="mailto:muazkh@gmail.com" target="_blank">muazkh@gmail.com</a>
            </p>
        </footer>
    
        <!-- commits.js is useless for you! -->
        <script src="https://cdn.webrtc-experiment.com/commits.js" async> </script>
    </body>
</html>
